package com.simple.relaxed.utils;

import com.simple.relaxed.manager.impl.AsyncTaskManager;
import com.simple.relaxed.service.ServiceBaseAbility;
import lombok.Getter;
import lombok.Setter;
import ohos.app.Context;
import ohos.app.dispatcher.task.TaskPriority;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class AsyncTaskUtil {

    public static class RunnableImpl implements Runnable {

        @Setter
        @Getter
        private volatile int stackMark;

        private volatile List<Map.Entry<Object, Method>> methods;

        @Setter
        @Getter
        private volatile Object param;

        @Setter
        @Getter
        private volatile ParamPassMonitor paramPassMonitor;

        public RunnableImpl() {
            methods = new ArrayList<>();
        }

        public RunnableImpl addTask(Object instance, Method method) {
            Map.Entry<Object, Method> methods = new AbstractMap.SimpleEntry<>(instance, method);
            this.methods.add(methods);
            return this;
        }

        @Override
        public void run() {
            for (Map.Entry<Object, Method> method : methods) {
                Object instance = method.getKey();
                Method m = method.getValue();
                m.setAccessible(true);
                try {
                    if (param != null) {
                        param = m.invoke(instance, param);
                    } else {
                        param = m.invoke(instance);
                    }
                } catch (InvocationTargetException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            if (paramPassMonitor != null) {
                paramPassMonitor.paramMonitor(param);
            }
        }
    }

    /**
     * 启动任务，通过bindName找到任务方法，并在指定的类型的线程中执行
     *
     * @param context     上下文对象
     * @param bindName    注册主任务时的名称
     * @param beforeStack 主任务在哪一类线程运行，目前只有两类线程，即UI线程以及非UI线程（BaseAbilitySlice.UI_STACK 以及 BaseAbilitySlice.OTHER_STACK）
     * @param asyncStack  主任务前置监听器运行在哪一类线程，目前只有两类线程，即UI线程以及非UI线程（BaseAbilitySlice.UI_STACK 以及 BaseAbilitySlice.OTHER_STACK）
     * @param afterStack  主任务完成时，回调任务运行在哪一类线程，目前只有两类线程，即UI线程以及非UI线程（BaseAbilitySlice.UI_STACK 以及 BaseAbilitySlice.OTHER_STACK）
     */
    public static void runAsync(Context context, String bindName, int beforeStack, int asyncStack, int afterStack) {
        // 初始化任务
        AsyncTaskManager.Entry entry = AsyncTaskManager.getInstance().lookup(bindName);
        Object beforeInstance = entry.getBeforeInstance();
        Method beforeTask = entry.getBeforeTask();
        Object asyncInstance = entry.getAsyncInstance();
        Method asyncTask = entry.getAsyncTask();
        Object afterInstance = entry.getAfterInstance();
        Method afterTask = entry.getAfterTask();
        List<Map.Entry<Integer, RunnableImpl>> tasks = new ArrayList<>();

        if (beforeTask != null) {
            RunnableImpl runnable = new RunnableImpl();
            runnable.setStackMark(beforeStack);
            Map.Entry<Integer, RunnableImpl> run = new AbstractMap.SimpleEntry<>(1, runnable.addTask(beforeInstance, beforeTask));
            tasks.add(run);
        }
        if (asyncTask != null) {
            if (tasks.isEmpty()) {
                RunnableImpl runnable = new RunnableImpl();
                runnable.setStackMark(asyncStack);
                Map.Entry<Integer, RunnableImpl> run = new AbstractMap.SimpleEntry<>(1, runnable.addTask(asyncInstance, asyncTask));
                tasks.add(run);
            } else {
                Map.Entry<Integer, RunnableImpl> e = tasks.get(0);
                RunnableImpl value = e.getValue();
                int stackMark = value.getStackMark();
                if (stackMark == asyncStack) {
                    value.addTask(asyncInstance, asyncTask);
                } else {
                    RunnableImpl runnable = new RunnableImpl();
                    runnable.setStackMark(asyncStack);
                    Map.Entry<Integer, RunnableImpl> run = new AbstractMap.SimpleEntry<>(2, runnable.addTask(asyncInstance, asyncTask));
                    tasks.add(run);
                }
            }
        } else {
            throw new NullPointerException("没有要执行的异步任务");
        }
        if (afterTask != null) {
            Map.Entry<Integer, RunnableImpl> e = tasks.get(tasks.size() - 1);
            RunnableImpl value = e.getValue();
            int stackMark = value.getStackMark();
            if (stackMark == afterStack) {
                value.addTask(afterInstance, afterTask);
            } else {
                RunnableImpl runnable = new RunnableImpl();
                runnable.setStackMark(afterStack);
                Map.Entry<Integer, RunnableImpl> run = new AbstractMap.SimpleEntry<>(tasks.size(), runnable.addTask(afterInstance, afterTask));
                tasks.add(run);
            }
        }
        // 前后任务关联
        for (int i = 0; i < tasks.size(); i++) {
            if (tasks.size() > 1 && i == tasks.size() - 1) {
                break;
            } else if (tasks.size() > 1) {
                Map.Entry<Integer, RunnableImpl> integerRunnableEntry = tasks.get(i);
                RunnableImpl value = integerRunnableEntry.getValue();
                int finalI = i;
                value.setParamPassMonitor(param -> {
                    Map.Entry<Integer, RunnableImpl> cache = tasks.get(finalI + 1);
                    int stackMark = value.getStackMark();
                    RunnableImpl runnable = cache.getValue();
                    runnable.setParam(param);
                    if (stackMark == runnable.getStackMark()) {
                        value.run();
                    } else {
                        if (stackMark == ServiceBaseAbility.UI_STACK) {
                            context.getUITaskDispatcher().asyncDispatch(runnable);
                        } else {
                            context.getGlobalTaskDispatcher(TaskPriority.DEFAULT).asyncDispatch(runnable);
                        }
                    }
                });
            }
        }
        runAsync(context, tasks.get(0));
    }

    private static void runAsync(Context context, Map.Entry<Integer, RunnableImpl> runnable) {
        RunnableImpl value = runnable.getValue();
        if (value.getStackMark() == ServiceBaseAbility.UI_STACK) {
            context.getUITaskDispatcher().asyncDispatch(value);
        } else {
            context.getGlobalTaskDispatcher(TaskPriority.DEFAULT).asyncDispatch(value);
        }
    }

    /**
     * 关键接口，通过此接口的对象，连接了前后两个Runnable对象，无论是否处于同一个线程中执行，都可以通过此对象，进行连接
     */
    public interface ParamPassMonitor {

        void paramMonitor(Object param);
    }
}
